feat(ui,serve): cross-project All Jobs and All Tokens views - #675
Merged
Conversation
Cross-project views are palette-reachable (no sidebar rows); their per-project sibling stays highlighted while open.
- GET /jobs multi-project merge now sorts globally by the requested sort_by/sort_order (default startTime desc, missing values last, deterministic (project_alias, id) tiebreak) instead of grouping by project alias; applies to CLI multi-project job list too (gotcha logged as vNEXT). - New GET /token/list endpoint: parallel fan-out over registered projects (project param repeatable, omitted = all), tokens stamped with project_alias, per-project failures degrade into errors[]; with_last_used applies the dormant-first sort globally. - New All Jobs page (#/jobs-all): single aggregated feed with Project column, client-side credit estimates (config/credits.ts) summed in the header, relative timestamps, extended status filter, partial- failure banner, cross-project detail drawer + deep links; entered via an All projects button on Jobs (reciprocal button goes back). Jobs page now also renders the previously ignored errors[]. - New All Tokens page (#/tokens-all): read-only audit across projects with opt-in last-used derivation; row click jumps to the project's Tokens page where mutations live. - Shared pieces extracted to jobsShared.tsx / tokensShared.tsx; cross-project pages are palette-only (sidebar keeps the per-project sibling highlighted).
…rror list list_tokens_all merged two different failure kinds into one errors list, so the All Tokens banner counted a healthy project with one degraded token as 'could not be listed'. Per-token lookup failures now come back under a separate token_errors key and render as their own strip.
padak
added a commit
that referenced
this pull request
Aug 23, 2026
* fix(ci): stop the live vNEXT gate turning main and every PR red `TestLiveRepositoryVnext::test_no_unresolved_placeholder_survives_a_release` asserted that the live tree carries no `(since vNEXT)` placeholder. That is not an invariant of this repo -- it is the opposite of the documented process. Since #648, a feature PR that documents version-gated behaviour writes the literal `vNEXT` placeholder and only the release PR rewrites it. CLAUDE.md says so directly ("Writing `vNEXT` in a feature PR is correct and stays green"), and TestReleaseModeSelection, added by the same PR as this assertion, explains that arming the gate outside a release PR "would demand a contributor delete a placeholder the process requires them to write". So main legitimately carries placeholders for most of a release cycle. The assertion was green only because #670 landed days after 0.90.0 had just rewritten every one of them. #675 added the first placeholder of the next cycle and the assertion went red -- on main, and on every open PR, since a PR run tests the merge commit. The release-time requirement itself is real and stays enforced where it can see the base branch's version: the "Unresolved vNEXT placeholder check" step in ci.yml (`--release-if-newer-than`) and its local twin `make vnext-check`. A unit test cannot see that version, so it cannot make this call. What a test CAN assert is that the live scan works, and that replaces it: every gate the scanner reports must point at a real line that really contains the placeholder. Zero hits and ten hits are both valid answers depending on where in the cycle the tree sits. The neighbouring "guards the guard" test already covers the globs resolving at all. * fix(test): anchor the live vNEXT scan on REPO_ROOT, not the cwd `VnextResidue.path` is repo-root-relative -- find_vnext_residue stores `path.relative_to(REPO_ROOT).as_posix()` -- so reading it back as a bare `Path(gate.path)` resolves against the current working directory. The loop body only executes when the tree actually carries a placeholder, which is precisely the state main is in now, so running pytest from anywhere but the repo root raised FileNotFoundError. Reproduced from tests/ before the change and confirmed green after, from both the repo root and a subdirectory. `REPO_ROOT / gate.path` also covers the one fallback branch, where a path outside the repo is stored absolute: joining an absolute right-hand side discards the left, yielding that path unchanged. Raised by Devin review on #678.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds cross-project ("all projects") views to the web UI, switchable right where it makes sense — a button on the per-project page:
#/jobs-all): one chronological feed across every registered project. Project column, client-side credit estimates per row + a header total over the currently shown rows, relative timestamps (raw ISO in the tooltip), extended status filter (processing/waiting/success/error/warning/terminated/cancelled), partial-failure banner, cross-project detail drawer (SSE logs, re-run/terminate) and shareable deep links (?sel=<alias>/<jobId>). Entered via an All projects button on Jobs; Current project only goes back. Polls at 15 s (vs 8 s per-project) since each tick fans out N Queue API calls server-side.#/tokens-all): read-only token audit across projects with the opt-in last-used derivation (dormant-first, now sorted globally). Row click jumps into that project's Tokens page where mint/rotate/revoke live. Secrets are never present.Both pages are command-palette-reachable (no extra sidebar rows; the per-project sibling stays highlighted).
Server changes
GET /jobsmulti-project merge now sorts globally by the requestedsort_by/sort_order(defaultstartTime desc), missing values last in both directions, deterministic(project_alias, id)tiebreak — instead of the old alias-then-id grouping that destroyed the per-project chronological order. This also applies to multi-project CLIjob list; logged in gotchas.md as(since vNEXT).GET /token/list: parallel fan-out over registered projects (projectrepeatable, omitted = all), rows stamped withproject_alias, per-project failures degrade intoerrors[]without aborting the rest,with_last_usedsupported with the per-token cost documented.errors[]envelope.Implementation notes
jobsShared.tsx/tokensShared.tsx(status colors, drawer, actions, scope/status cells); extraction is behavior-preserving for the per-project pages.web/frontend/src/config/credits.tsand are an estimate (duration × per-component rate × container size), labeled as such in the UI.vNEXT.Testing
pytest tests/full suite green (6047 passed); new coverage for global sort semantics (7 tests) andlist_tokens_allaggregation/partial failure/ordering (router forwarding included).tsc --noEmitclean,vitest97 tests green (32 new: credit rate matching, formatCredits boundaries, relative time, token expiry/last-used helpers).kbagent serve --ui): chronological cross-project merge, credits total reacting to the status filter, cross-project drawer + deep-link restore, last-used dormant-first sort, partial-failure banners.